#!/usr/bin/env python
# encoding: utf-8


"""
@file: triangle_condition_converts.py
@time: 2017/2/15 下午7:59
"""
from functools import reduce
from mathsolver.functions.base import *
from sympy import sin, cos, symbols, factor, expand, expand_trig, trigsimp, pi, tan, cot
from mathsolver.functions.budengshi import common_opers as co
from mathsolver.functions.sanjiao.bianjiaozhuanhuan import JiaoHuaBian, BianHuaJiao
from mathsolver.functions.sanjiao.triangle_constant import TRIANGLE_ANGLES_SET
from mathsolver.functions.sanjiao.triangle_structs import TriangleKnowledgeElement
from mathsolver.functions.sanjiao import sanjiao_utils as su


# 三角形已知条件转换
# 345409, 已知△ABC中,cotA=-\\frac{12}{5},则cosA=()
# 最简单的已知cot, tan, sin, cos中的一个值求其他三个值
def _convert1(cond_eq):
    kds = []

    cond_l, cond_r = cond_eq.sympify()
    cond_f = cond_l - cond_r
    cond_symbs = list(cond_f.free_symbols)
    if len(cond_symbs) != 1:
        raise Exception('Type Match Error')
    cond_symb = cond_symbs[0]
    cond_subs = ((sin(cond_symb), 'SIN'), (cos(cond_symb), 'COS'), (tan(cond_symb), 'TAN'), (cot(cond_symb), 'COT'))
    eqs = [['SIN**2 + COS**2', '1'], ['TAN*COS', 'SIN'], ['COT*SIN', 'COS'], [cond_f.subs(cond_subs), '0']]
    # values_list = co.solve_poly_eqs(BaseEqs(eqs))
    values_list = co.isolve_eqs(BaseEqs(eqs))
    matched = True
    for values in values_list:
        matched = matched and reduce(lambda b1, b2: b1 and b2, map(lambda pair: pair[1].is_real, values))
    if not matched:
        raise Exception('Type Match Error')
    cond_reverse_subs = map(lambda pair: (pair[1], pair[0]), cond_subs)
    new_values_list = []
    for values in values_list:
        tmp_values = map(lambda pair: [pair[0].subs(cond_reverse_subs), pair[1]], values)
        if dict(tmp_values)[sin(cond_symb)] > 0:
            new_values_list.append(tmp_values)
    for _eq in new_values_list[0]:
        k_d = TriangleKnowledgeElement(cond_eq)
        k_d.set_output(BaseEq(_eq))  # 知识点转换后的结果
        k_d.add_step(['\because ' + cond_eq.printing(), '\therefore ' + BaseEq(_eq).printing()])
        kds.append(k_d)
    return new_values_list[0], kds  # old:new_values_list[0]
    # result = {}
    # for values in new_values_list:
    #     for k, v in values:
    #         new_v = result.get(k, [])
    #         new_v.append(v)
    #         result[k] = new_v
    # return result[0]


# print _convert1(BaseEq(['cot(A)', '-12/5']))


# 488952,设△ABC的内角A、B、C的对边长分别为a、b、c,cos(A-C)+cosB=\\frac{3}{2},b^{2}=ac,求B.
# △ABC在内角A、B、C的对边分别为a,b,c,已知a=bcosC+csinB.【使用正弦定理】
def _convert2(cond_eq):
    """
    边角转换
    :param cond_eq:
    :return:
    >>> _convert2(BaseEq(['a + b', 'a*cot(A) + b*cot(B)'])).sympify()
    [[sin(A) + sin(B) - cos(A) - cos(B), 0]]
    >>> _convert2(BaseEq(['a', '2*b*sin(A)'])).sympify()
    [[-2*sin(B) + 1, 0]]
    >>> _convert2(BaseEq(['a', 'b*cos(C)+c*sin(B)'])).sympify()
    [[sin(A) - sin(B)*sin(C) - sin(B)*cos(C), 0]]
    """
    result_eqs = []
    kds = []
    _solver1 = JiaoHuaBian(verbose=True).solver(cond_eq)  # 角化边
    _prev_steps = _solver1.steps  # 角化边的步骤
    side_eqs = _solver1.output[0]  # 角化边的结果
    side_subs = (('a', 1), ('b', 1), ('c', 1))
    for side_eq_l, side_eq_r in side_eqs.sympify():
        side_eq_f = side_eq_l - side_eq_r
        if not side_eq_f.subs(side_subs).free_symbols:
            symb_values = solve(side_eq_f)
            verify = True
            for s_v in symb_values:
                if not s_v:
                    verify = False
            if verify:  # 如果角化边后只含有边的关系
                # k_e.add_label('三角形角化边')
                result_eqs.append([side_eq_f, '0'])
                kd = TriangleKnowledgeElement(cond_eq)
                for step in _prev_steps:
                    kd.add_step(step)
                kd.add_label('三角形角化边')
                kd.set_output(BaseEq([side_eq_f, '0']))
                kd.add_step(['\\because ' + BaseEq([side_eq_f, '0']).printing(),
                             '使用正弦定理得:' + BaseEq([side_eq_f, '0']).printing()])
                kds.append(kd)
    _solver = BianHuaJiao(verbose=True).solver(cond_eq)
    _prev_steps = _solver.steps  # 边化角的步骤
    angle_eq = _solver.output[0]  # 边化角 边化为角只包含一个等式
    angle_subs = (('sin(A)', '1'), ('cos(A)', '1'), ('tan(A)', '1'), ('cot(A)', '1'),
                  ('sin(B)', '1'), ('cos(B)', '1'), ('tan(B)', '1'), ('cot(B)', '1'),
                  ('sin(C)', '1'), ('cos(C)', '1'), ('tan(C)', '1'), ('cot(C)', '1'))
    angle_eq_l, angle_eq_r = angle_eq.sympify()
    angle_eq_f = angle_eq_l - angle_eq_r
    if not angle_eq_f.subs(angle_subs).free_symbols:
        result_eqs.append([angle_eq_f, '0'])
        kd = TriangleKnowledgeElement(cond_eq)
        kd.add_label('三角形角化边')
        for step in _prev_steps:
            kd.add_step(step)
        kd.set_output(BaseEq([angle_eq_f, '0']))
        kd.add_step(['\\because ' + angle_eq.printing(), '使用余弦定理得:' + BaseEq([angle_eq_f, '0']).printing()])
        kds.append(kd)
    elif not expand_trig(angle_eq_f).subs(angle_subs).free_symbols:  # 展开后
        angle_eq_f = expand(expand_trig(angle_eq_f))
        result_eqs.append([angle_eq_f, '0'])
        kd = TriangleKnowledgeElement(cond_eq)
        kd.add_label('三角形角化边')
        for step in _prev_steps:
            kd.add_step(step)
        kd.set_output(BaseEq([angle_eq_f, '0']))
        kd.add_step(['\\because ' + angle_eq.printing(), '使用余弦定理得:' + BaseEq([angle_eq_f, '0']).printing()])
        kds.append(kd)
    return result_eqs, kds


# 5*sin(A)*cos(B) - 5*sin(B)*cos(A) - 3*sin(C) = 0
def _convert3(cond_eq):
    cond_l, cond_r = cond_eq.sympify()
    cond_f = cond_l - cond_r
    symbs = list(cond_f.free_symbols)
    from mathsolver.functions.sanjiao import sanjiao_utils as su
    if not (len(symbs) == 3 and su.i_is_subset(symbs, TRIANGLE_ANGLES_SET)):
        raise Exception('Type Match Error')
    result_eqs = []
    kds = []
    angle_subs = (('A', 'pi-(B+C)'), ('B', 'pi-(A+C)'), ('C', 'pi-(A+B)'))
    for angle_sub in angle_subs:
        tmp_f = expand_trig(cond_f.subs(*angle_sub))
        items = tmp_f.as_coefficients_dict().items()
        if len(items) != 2:
            continue
        result_eqs.append([tmp_f, '0'])
        kd = TriangleKnowledgeElement(cond_eq)
        kd.add_label('三角形内角和')
        kd.set_output(BaseEq([tmp_f, '0']))
        kd.add_step(['\\because ' + BaseEq(['A+B+C', pi]).printing(),
                     '\\therefore ' + cond_eq.printing() + '得出' + BaseEq([tmp_f, '0']).printing()])
        kds.append(kd)
    return result_eqs, kds


# sin(B+C) = sin(pi - A)
def _convert4(cond_eq):
    """
    :param cond_eq: 
    :return: 
    >>> _convert4(BaseEq(['3*cos(B-C) - 1', '6*cos(B)*cos(C)']))
    [[3*cos(A), 1]]
    """

    cond_l, cond_r = cond_eq.sympify()
    cond_f = cond_l - cond_r
    trig_mon, const = co.split_mons_const(cond_f)
    result_eqs = []
    kds = []
    sim_trig_mon = trigsimp(trig_mon)
    angle_subs = (('B+C', 'pi-A'), ('A+C', 'pi-B'), ('A+B', 'pi-C'))
    f = sim_trig_mon.subs(angle_subs)
    result_eqs.append([f, -const])
    kd = TriangleKnowledgeElement(cond_eq)
    kd.set_output(BaseEq([f, -const]))
    kd.add_label('三角形内角和')
    kd.add_step(['\\because ' + BaseEq(['A+B+C', pi]).printing(),
                 '\\therefore ' + cond_eq.printing() + '得出' + BaseEq([f, -const]).printing()])
    kds.append(kd)
    return result_eqs, kds


# 使用二倍角公式
def _convert5(cond_eq):
    """
    使用二倍角公式
    :param cond_eq: 
    :return: 
    """
    _A, _B, _C = symbols('A, B, C')
    cond_l, cond_r = cond_eq.sympify()
    cond_f = cond_l - cond_r
    double_angles = []
    if cond_f.has(cos(2 * _A)):
        double_angles.append(_A)
    if cond_f.has(cos(2 * _B)):
        double_angles.append(_B)
    if cond_f.has(cos(2 * _C)):
        double_angles.append(_C)
    double_angles_expand = map(lambda angle: (2 * cos(angle) ** 2 - 1, 1 - 2 * sin(angle) ** 2), double_angles)
    combins = list(co.combin_iters(*double_angles_expand))
    result_eqs = []
    kds = []
    for subs in combins:
        tmp_f = cond_f
        for sub in subs:
            symb = list(sub.free_symbols)[0]
            tmp_f = tmp_f.subs(cos(2 * symb), sub)
        result_eqs.append([tmp_f, '0'])
        kd = TriangleKnowledgeElement(cond_eq)
        kd.set_output(BaseEq([tmp_f, '0']))
        kd.add_step(['由二倍角公式得:', new_latex(cond_f) + '=' + new_latex(tmp_f)])
        kds.append(kd)
    return result_eqs, kds


# 三角形内角和
# sin(A) + sin(C) = 2*sin(B)
# sin(A) + sin(C) = 2*sin(pi - (A+C))
def _convert6(cond_eq):
    cond_l, cond_r = cond_eq.sympify()
    cond_f = cond_l - cond_r
    angle_subs = (('A', 'pi-(B+C)'), ('B', 'pi-(A+C)'), ('C', 'pi-(A+B)'))
    result_eqs = []
    kds = []
    # 只有三个角度的时候采用这个公司
    symbs = cond_f.free_symbols
    if not (su.i_is_subset(symbs, TRIANGLE_ANGLES_SET) and len(symbs) == 3):
        return result_eqs, kds
    for angle_sub in angle_subs:
        tmp_f = cond_f.subs(*angle_sub)
        if len(tmp_f.free_symbols) == 2:
            f2 = expand_trig(tmp_f)
            f3 = factor(f2)
            if f3 != f2 and len(f3.as_coefficients_dict().items()) == 1:  # 如果可以因式分解
                result_eqs.append([f3, 0])
                kd = TriangleKnowledgeElement(cond_eq)
                kd.set_output(BaseEq([f3, '0']))
                kd.add_label('三角形内角和')
                kd.add_step(['\\because ' + BaseEq(['A+B+C', pi]).printing(),
                             '\\therefore ' + cond_eq.printing() + '得出' + BaseEq([f3, '0']).printing()])
                kds.append(kd)
    return result_eqs, kds


_converts = [_convert1, _convert2, _convert3, _convert4, _convert5]  # _convert6


def condition_converts(k_e):
    def _already_in(_eq, _eqs):
        _l, _r = BaseEq(_eq).sympify()
        _f = _l - _r
        for tmp_eq in _eqs:
            _l1, _r1 = BaseEq(tmp_eq).sympify()
            _f1 = _l1 - _r1
            if _f == _f1:
                return True
        return False

    eq = k_e.get_output()
    convert_eqs = [eq.sympify()]
    k_es = [k_e]
    for convert in _converts:
        try:
            eqs, kds = convert(eq)
            if len(eqs) == 1 and _already_in(eqs[0], convert_eqs):  # 如果已经存在 咋不用添加
                continue
            for kd in kds:
                kd.set_parent(k_e)
            k_es.extend(kds)
            convert_eqs.extend(eqs)
        except Exception:
            pass
    return convert_eqs, k_es


if __name__ == '__main__':
    pass
